/**
 * ProtoActor-TS PingPong 示例
 * 使用 Bun 运行: bun run src/examples/pingpong.ts
 */

import { Actor, Context, PID, Props, RootContexts, ActorSystem } from '../actor';

// 定义消息类型
interface PingMessage {
  count: number;
}

interface PongMessage {
  count: number;
}

// 定义 Ping Actor
class PingActor implements Actor {
  private pongPid: PID | null = null;
  private count: number = 0;
  private maxCount: number = 10;

  constructor(maxCount: number = 10) {
    this.maxCount = maxCount;
  }

  receive(context: Context): void {
    const message = context.message();

    // 启动 ping-pong 序列
    if (message === 'start' && this.pongPid) {
      console.log('PingActor 收到开始命令');
      this.count = 0;
      context.send(this.pongPid, { count: this.count } as PingMessage);
    } 
    // 处理来自 pong 的回复
    else if (this.isPongMessage(message)) {
      this.count = message.count;
      console.log(`PingActor 收到 Pong ${this.count}`);
      
      if (this.count >= this.maxCount) {
        console.log('PingActor 完成序列');
        // 可以在这里停止 actors
        return;
      }
      
      // 使用 Bun 的 setTimeout 延迟一点，让输出更易读
      setTimeout(() => {
        if (this.pongPid) {
          context.send(this.pongPid, { count: this.count } as PingMessage);
        }
      }, 100);
    }
    // 设置 pong actor 的引用
    else if (message instanceof PID) {
      console.log('PingActor 收到 PongActor PID');
      this.pongPid = message;
    }
  }

  // 类型守卫
  private isPongMessage(message: any): message is PongMessage {
    return message && typeof message === 'object' && 'count' in message;
  }
}

// 定义 Pong Actor
class PongActor implements Actor {
  receive(context: Context): void {
    const message = context.message();
    
    // 处理来自 ping 的消息
    if (this.isPingMessage(message)) {
      const count = message.count + 1;
      console.log(`PongActor 收到 Ping ${message.count}, 回复 Pong ${count}`);
      
      // Bun 对异步操作有更好的性能
      setTimeout(() => {
        context.sender().tell({ count: count } as PongMessage);
      }, 50);
    }
  }

  // 类型守卫
  private isPingMessage(message: any): message is PingMessage {
    return message && typeof message === 'object' && 'count' in message;
  }
}

/**
 * 运行 PingPong 示例
 */
async function runPingPong() {
  console.log('========================================');
  console.log('| ProtoActor-TS PingPong 示例 (Bun)    |');
  console.log('========================================');

  // 创建 actor 系统
  const system = new ActorSystem();
  const rootContext = RootContexts.create(system);

  try {
    // 创建 pong actor
    const pongProps = Props.fromProducer(() => new PongActor());
    const pongPid = rootContext.spawn(pongProps);
    console.log(`PongActor 创建成功: ${pongPid.toString()}`);

    // 创建 ping actor，设置最大计数为 10
    const pingProps = Props.fromProducer(() => new PingActor(10));
    const pingPid = rootContext.spawn(pingProps);
    console.log(`PingActor 创建成功: ${pingPid.toString()}`);

    // 向 ping actor 发送 pong actor 的引用
    rootContext.send(pingPid, pongPid);

    // 延迟一下，确保 PID 设置好了
    await new Promise(resolve => setTimeout(resolve, 100));

    // 开始 ping-pong 序列
    console.log('开始 Ping-Pong 序列...');
    rootContext.send(pingPid, 'start');

    // 运行一段时间后关闭
    setTimeout(() => {
      console.log('停止 Actors...');
      rootContext.stop(pingPid);
      rootContext.stop(pongPid);
      console.log('PingPong 示例完成');
    }, 5000);
  } catch (error) {
    console.error('PingPong 示例运行失败:', error);
  }
}

// 如果直接运行此文件
if (import.meta.main) {
  runPingPong();
}

// 导出函数供其他模块使用
export { runPingPong }; 